package com.osi.project.common.business;

import com.alibaba.druid.filter.Filter;
import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.wall.WallConfig;
import com.alibaba.druid.wall.WallFilter;
import com.github.pagehelper.PageInterceptor;
import com.osi.project.common.intercaptor.SqlLogInterceptor;
import com.osi.start.common.business.dao.BaseDao;
import com.osi.start.common.helper.CollectionHelper;
import com.osi.start.framework.web.servlet.MybatisSqlInterceptor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.session.SqlSessionFactory;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import tk.mybatis.spring.mapper.MapperScannerConfigurer;

import javax.sql.DataSource;
import java.util.List;
import java.util.Properties;

/**
 * MyBatis扫描接口，使用的tk.mybatis.spring.mapper.MapperScannerConfigurer
 */
@Slf4j
@AutoConfigureAfter(SqlLogInterceptor.class)
@Configuration
@EnableTransactionManagement
public class TkMapperScannerConfig {

	@Bean(initMethod = "init", destroyMethod = "close")
	public DruidDataSource druidDataSource(@Autowired DbConfig captialDbConfig) throws Exception {
		return dataSource(captialDbConfig);
	}

	private DruidDataSource dataSource(DbConfig config) throws Exception {
		DruidDataSource druidDataSource = new DruidDataSource();
		druidDataSource.setDriverClassName(config.getDriverClassName());
		druidDataSource.setUrl(config.getUrl());
		druidDataSource.setUsername(config.getUsername());
		// druidDataSource.setPassword(RSAUtils.decryptByPrivateKey(config.getPassword(),
		// coreProperties.getEncrypt().getPrivateKey()));
		druidDataSource.setPassword(config.getPassword());
		druidDataSource.setInitialSize(config.getInitialSize());
		druidDataSource.setMinIdle(config.getMinIdle());
		druidDataSource.setMaxActive(config.getMaxActive());
		druidDataSource.setMaxWait(config.getMaxWait());
		druidDataSource.setTimeBetweenEvictionRunsMillis(config.getTimeBetweenEvictionRunsMillis());
		druidDataSource.setMinEvictableIdleTimeMillis(config.getMinEvictableIdleTimeMillis());
		// 此项如果为空，下面几个test都不会生效
		druidDataSource.setValidationQuery(config.getValidationQuery());
		druidDataSource.setTestWhileIdle(config.getTestWhileIdle());
		druidDataSource.setTestOnBorrow(config.getTestOnBorrow());
		druidDataSource.setTestOnReturn(config.getTestOnReturn());
		// 5.5以后的mysql开启，以后的关闭
		druidDataSource.setPoolPreparedStatements(config.getPoolPreparedStatements());
		druidDataSource
				.setMaxPoolPreparedStatementPerConnectionSize(config.getMaxPoolPreparedStatementPerConnectionSize());
		// filter
		druidDataSource.setFilters(config.getFilters());
		initMultiStatementAllow(druidDataSource);

		druidDataSource.setConnectionProperties(config.getConnectionProperties());
		return druidDataSource;
	}

	@Bean("tkSqlSessionFactory")
	public SqlSessionFactory tkSqlSessionFactory(@Autowired DruidDataSource druidDataSource)
			throws Exception {
		return sqlSessionFactory(druidDataSource);
	}

	@Bean("tkMapperScanner")
	public MapperScannerConfigurer tkMapperHelper() {
		log.info("User MapperScannerConfigurer mapperHelper init ");
		Properties properties = new Properties();
		// 数据库方言（主要用于：取回主键的方式）
		properties.setProperty("IDENTITY", "MYSQL");
		properties.setProperty("notEmpty", "false");

		MapperScannerConfigurer scan = new MapperScannerConfigurer();
		//		scan.setSqlSessionFactoryBeanName("sqlSessionFactory"); // 多数据源时，必须配置
		scan.setSqlSessionFactoryBeanName("tkSqlSessionFactory");
		scan.setProperties(properties);
		scan.setBasePackage("com.osi.project.**.dao,com.osi.project.**.generate.dao");
		scan.setMarkerInterface(BaseDao.class);

		return scan;
	}

	@Bean
	public DataSourceTransactionManager transactionManager(@Autowired DruidDataSource druidDataSource) throws Exception {
		return new DataSourceTransactionManager(druidDataSource);
	}

	private SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
		SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
		sqlSessionFactoryBean.setDataSource(dataSource);
		PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
		sqlSessionFactoryBean.setMapperLocations(resolver.getResources(getMapperXmlLocation()));

		sqlSessionFactoryBean.setPlugins(new Interceptor[] {new MybatisSqlInterceptor(), getPageInterceptor() });

		return sqlSessionFactoryBean.getObject();
	}

	private PageInterceptor getPageInterceptor() {
		PageInterceptor pageInterceptor = new PageInterceptor();
		Properties properties = new Properties();
		properties.setProperty("helperDialect", "mysql");
		properties.setProperty("reasonable", "false");
		properties.setProperty("supportMethodsArguments", "false");
		properties.setProperty("returnPageInfo", "count=check");
		properties.setProperty("params", "count=countSql");
		pageInterceptor.setProperties(properties);
		return pageInterceptor;
	}

	public String getMapperXmlLocation() {
		return "classpath*:mapper/**/**/**.xml";
	}

	/**
	 * 初始化设置允许执行多语句
	 * 
	 * @param druidDataSource
	 */
	private void initMultiStatementAllow(DruidDataSource druidDataSource) {
		List<Filter> filters = druidDataSource.getProxyFilters();
		if (CollectionHelper.isEmpty(filters)) {
			return;
		}

		for (Filter filter : filters) {
			if (filter instanceof WallFilter) {
				WallFilter wallFilter = (WallFilter) filter;
				WallConfig wallConfig = wallFilter.getConfig();
				if (null == wallConfig) {
					wallConfig = new WallConfig();
					wallFilter.setConfig(wallConfig);
					wallConfig.setMultiStatementAllow(true);
					wallConfig.setNoneBaseStatementAllow(true);
				}
				break;
			}
		}
	}

}
